package com.lhd.qd.module.system.user.service.impl;

import com.lhd.qd.common.base.BaseServiceImpl;
import com.lhd.qd.common.consts.RedisConsts;
import com.lhd.qd.common.consts.dict.UserStateEnum;
import com.lhd.qd.common.exception.BusinessException;
import com.lhd.qd.common.util.CommonUtils;
import com.lhd.qd.common.util.RedisUtils;
import com.lhd.qd.common.util.SecurityUtils;
import com.lhd.qd.common.util.TokenUtils;
import com.lhd.qd.config.QdProperties;
import com.lhd.qd.module.system.resource.service.ResourceService;
import com.lhd.qd.module.system.user.dao.UserMapper;
import com.lhd.qd.module.system.user.model.converter.AbstractUserConverter;
import com.lhd.qd.module.system.user.model.dataobj.UserDO;
import com.lhd.qd.module.system.user.model.dto.LoginDTO;
import com.lhd.qd.module.system.user.model.dto.UserInfoDTO;
import com.lhd.qd.module.system.user.model.vo.LoginVO;
import com.lhd.qd.module.system.user.service.LoginService;
import com.lhd.qd.module.system.user.service.UserLoginLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;

@Service
public class LoginServiceImpl extends BaseServiceImpl<UserMapper, UserDO> implements LoginService {

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private QdProperties qdProperties;

    @Autowired
    private UserLoginLogService loginLogService;

    @Override
    public LoginVO login(LoginDTO dto, Map<String, String> clientMap) {

        UserInfoDTO userInfoDTO = getUserByUsername(dto.getUsername());

        try {
            checkUserInfo(userInfoDTO, dto.getPassword());
        } catch (BusinessException e) {
            loginLogService.saveUserLoginLog(dto.getUsername(), LocalDateTime.now(), false, e.getMessage(), clientMap);
            throw e;
        }

        Long userId = userInfoDTO.getId();

        String[] permissions = resourceService.getOperatePermissionListByRoleId(userInfoDTO.getRoleId());
        Map<String, Object> userInfoMap = AbstractUserConverter.INSTANCE.infoDTO2Map(userInfoDTO, permissions);
        RedisUtils.hashPutAll(
                RedisConsts.KEY_USER_INFO + userId,
                userInfoMap);

        LoginVO loginVO = new LoginVO();
        loginVO.setToken(TokenUtils.generate(userId, qdProperties.getTokenExpireTime()));
        loginVO.setUserInfo(AbstractUserConverter.INSTANCE.infoDTO2InfoVO(userInfoDTO));
        loginVO.setMenuList(resourceService.getMenuListByRoleId(userInfoDTO.getRoleId()));
        loginVO.setPermissionMap(resourceService.getOperatePermissionListWithMenuByRoleId(userInfoDTO.getRoleId()));

        setLoginLog(userId, userInfoDTO.getUsername(), clientMap);

        return loginVO;
    }

    public void setLoginLog(Long userId, String username, Map<String, String> clientMap) {

        LocalDateTime loginTime = LocalDateTime.now();

        UserDO dataObj = new UserDO();
        dataObj.setId(userId);
        dataObj.setLoginTime(loginTime);
        dataObj.setLoginIp(CommonUtils.ip2Long(clientMap.get("client-ipv4")));
        baseMapper.updateLoginInfo(dataObj);

        loginLogService.saveUserLoginLog(username, loginTime, true, "", clientMap);
    }

    private void checkUserInfo(UserInfoDTO userInfoDTO, String inputPassword) {

        if (userInfoDTO == null) {
            throw new BusinessException("用户名或密码错误");
        }

        String encryptPassword = SecurityUtils.md5WithSalt(
                inputPassword,
                userInfoDTO.getSalt(),
                qdProperties.getPasswordSaltTimes());
        if (!encryptPassword.equals(userInfoDTO.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }

        if (userInfoDTO.getEmployeeId() == null || userInfoDTO.getEmployeeId() <= 0) {
            throw new BusinessException("用户未关联员工");
        }

        if (userInfoDTO.getHospitalId() == null || userInfoDTO.getHospitalId() <= 0) {
            throw new BusinessException("用户未设置医院");
        }

        if (userInfoDTO.getDeptId() == null || userInfoDTO.getDeptId() <= 0) {
            throw new BusinessException("用户未设置科室");
        }

        if (userInfoDTO.getRoleId() == null || userInfoDTO.getRoleId() <= 0) {
            throw new BusinessException("用户未设置角色");
        }

        if (UserStateEnum.DISABLED.getCode().equals(userInfoDTO.getStateCode())) {
            throw new BusinessException("用户已禁用，请联系管理员启用。");
        }

        if (UserStateEnum.LOCKED.getCode().equals(userInfoDTO.getStateCode())) {
            throw new BusinessException("用户已锁定，请联系管理员解锁。");
        }
    }

    private UserInfoDTO getUserByUsername(String username) {

        return baseMapper.selectUserByUsername(username);
    }
}
